home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ADA Programming Guide
/
ADA Programming Guide.iso
/
ada_gwu
/
type.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-01-30
|
61KB
|
1,867 lines
/*
* Copyright (C) 1985-1992 New York University
*
* This file is part of the Ada/Ed-C system. See the Ada/Ed README file for
* warranty (none) and distribution info and also the GNU General Public
* License for more details.
*/
#define GEN
#include "hdr.h"
#include "vars.h"
#include "segment.h"
#include "gvars.h"
#include "attr.h"
#include "ops.h"
#include "type.h"
#include "axqrp.h"
#include "setp.h"
#include "dbxp.h"
#include "initobjp.h"
#include "maincasp.h"
#include "gmainp.h"
#include "arithp.h"
#include "segmentp.h"
#include "genp.h"
#include "exprp.h"
#include "gutilp.h"
#include "arithp.h"
#include "genp.h"
#include "miscp.h"
#include "gmiscp.h"
#include "smiscp.h"
#include "statp.h"
#include "typep.h"
static void init_enum(Symbol, Segment, int, int);
static void install_type(Symbol, Segment, int);
static Segment make_fixed_template(Const, Const, Const, Const,
struct tt_fx_range **);
static void split_powers(int *);
static void process_record(Symbol);
static int linearize_record(Tuple, Node);
static int discr_dep_subtype(Node);
static void get_discr(Node, int *, int *);
static void eval_max_size(Symbol, Tuple);
#define TT_PTR(p) (int **) p
extern Segment CODE_SEGMENT, DATA_SEGMENT, DATA_SEGMENT_MAIN;
extern Segment VARIANT_TABLE, FIELD_TABLE;
extern int ADA_MIN_INTEGER, ADA_MAX_INTEGER;
extern *ADA_MIN_INTEGER_MP, *ADA_MAX_INTEGER_MP;
extern long ADA_MIN_FIXED, ADA_MAX_FIXED;
extern int *ADA_MIN_FIXED_MP, *ADA_MAX_FIXED_MP;
static char *PRECISION_NOT_SUPPORTED =
"Precision not supported by implementation. (Appendix F)";
/* split_ variables use to report result from split_powers()*/
static int split_powers_2, split_powers_5, split_powers_value;
/* Chapter 3: types */
/* type elaboration */
void gen_type(Symbol type_name) /*;gen_type*/
{
/* This is the main procedure for type elaboration.
*
* type_name : in the case of a type declaration, this is the
* name of the type.
*/
Node l_node, u_node, d_node, s_node, low_node, high_node, entry_node;
Node name_node, pragma_id, pragma_list, pragma_op, pragma_val, value_node;
Symbol parent_type, comp_type, typ, entry_name, entry_type, index;
Symbol indx_type, task_proc;
Tuple type_list, index_list, tup, sig, entry_list;
int nb_dim, lng, priority, offset;
long nb_elements, nb_len; /* long to avoid overflow problems */
int family_number, len, global_flag, ubd, lbd;
int collection_size;
Tuple repr_tup;
Const low_const, high_const, delta_const, small_const;
Segment stemplate, static_template, non_static_template;
Fortup ft1;
struct tt_array *tt_array_ptr;
struct tt_e_range *tt_e_range_ptr;
struct tt_access *tt_access_ptr;
struct tt_task *tt_task_ptr;
struct tt_fx_range *tt_fx_range_ptr;
#ifdef TRACE
if (debug_flag)
gen_trace_symbol("GEN_TYPE", type_name);
#endif
switch(NATURE(type_name)) {
case(na_type):
/* Case of FIXED types for which we create a template.
* Also case of derived types.
*/
if (is_fixed_type(type_name)) {
sig = SIGNATURE(type_name);
l_node = (Node) sig[2];
u_node = (Node) sig[3];
d_node = (Node) sig[4];
s_node = (Node) sig[5];
low_const = get_ivalue(l_node);
high_const = get_ivalue(u_node);
delta_const = get_ivalue(d_node);
small_const = get_ivalue(s_node);
stemplate = make_fixed_template(low_const, high_const, delta_const,
small_const, &tt_fx_range_ptr);
/* SETL ver supports 2 kinds of fixed point, in C we have only 1 */
tt_fx_range_ptr->fxlow = ADA_MIN_FIXED + 1;
tt_fx_range_ptr->fxhigh = ADA_MAX_FIXED;
TYPE_KIND(type_name) = TK_LONG;
TYPE_SIZE(type_name) = su_size(TK_LONG);
install_type(type_name, stemplate, TRUE);
root_type(type_name) = type_name;
}
else { /* Derived type */
parent_type = TYPE_OF(type_name);
assign_same_reference(type_name, parent_type);
TYPE_KIND(type_name) = TYPE_KIND(parent_type);
TYPE_SIZE(type_name) = TYPE_SIZE(parent_type);
}
break;
case(na_array):
tup = (Tuple) SIGNATURE(type_name);
index_list = (Tuple) tup[1];
comp_type = (Symbol) tup[2];
if (is_entry_type(comp_type))
return;
nb_dim = tup_size(index_list);
nb_elements = 1L;
FORTUP(index = (Symbol), index_list, ft1);
len = length_of(index);
if (len >= 0)
nb_elements *= len;
else
nb_elements = -1L;
ENDFORTUP(ft1);
if ((nb_elements >= 0L) && has_static_size(comp_type)) {
/* want TYPE_SIZE to be number of storage units for array , */
/* TBSL: check that TYPE_KIND assignment below right,
* as in SETL just have TYPE_SIZE assignment of course
*/
TYPE_KIND(type_name) = TYPE_KIND(comp_type);
nb_len= nb_elements * TYPE_SIZE(comp_type);
if (nb_len > MAX_STATIC_SIZE) nb_len = -1;
TYPE_SIZE(type_name) = nb_len;
}
else {
TYPE_SIZE(type_name) = -1;
}
stemplate = template_new(TT_U_ARRAY, size_of(type_name),
WORDS_ARRAY - 4, TT_PTR(&tt_array_ptr));
/* TBSL: need to define field TT_U_ARRAY_DIMENSIONS: byte or integer? */
tt_array_ptr->dim = nb_dim;
global_flag = has_static_size(type_name);
type_list = tup_copy(index_list);
type_list = (Tuple) tup_with(type_list, (char *) comp_type);
while(tup_size(type_list)) {
typ = (Symbol) tup_frome(type_list);
reference_of(typ);
/* template +:= ref; */
segment_put_int(stemplate, REFERENCE_SEGMENT);
segment_put_int(stemplate, (int) REFERENCE_OFFSET);
global_flag &= is_global(typ);
}
tup_free(type_list);
install_type(type_name, stemplate, global_flag);
break;
case(na_record):
process_record(type_name);
break;
case(na_enum):
/* this one is certainly static... */
sig = SIGNATURE(type_name);
low_node = (Node) sig[2];
high_node = (Node) sig[3];
lbd = get_ivalue_int(low_node);
ubd = get_ivalue_int(high_node);
stemplate = template_new(TT_ENUM, 1, WORDS_E_RANGE,
TT_PTR(&tt_e_range_ptr));
tt_e_range_ptr->elow = lbd;
tt_e_range_ptr->ehigh = ubd;
init_enum(type_name, stemplate, lbd, ubd);
/* TYPE_SIZE(type_name) = ubd <= 255 ? mu_size(mu_byte) :
mu_size(mu_word); */
TYPE_KIND(type_name) = TK_WORD; /* only word case for 1st version */
TYPE_SIZE(type_name) = 1; /* only word case for 1st version ds*/
/* put that in the static segment.... */
install_type(type_name, stemplate, TRUE);
break;
case(na_access):
/* Needs own template, as the accessed type contains a task
* (otherwise expander changed it to derived type from $ACCESS).
*/
TYPE_KIND(type_name) = TYPE_KIND(symbol_daccess);
TYPE_SIZE(type_name) = TYPE_SIZE(symbol_daccess);
stemplate = template_new(TT_ACCESS, size_of(type_name),
WORDS_ACCESS, TT_PTR(&tt_access_ptr));
tt_access_ptr->master_task = 0;
tt_access_ptr->master_bfp = 0;
repr_tup = REPR(type_name);
if (repr_tup == (Tuple)0) /* error condition */
value_node = OPT_NODE;
else
value_node = (Node) repr_tup[3];
if (N_KIND(value_node) == as_opt) {
tt_access_ptr->collection_size = ADA_MAX_INTEGER;
tt_access_ptr->collection_avail = ADA_MAX_INTEGER;
}
else if (N_KIND(value_node) == as_ivalue) {
collection_size = INTV((Const)N_VAL(value_node));
tt_access_ptr->collection_size = collection_size;
tt_access_ptr->collection_avail = collection_size;
}
install_type(type_name, stemplate, FALSE);
if ((N_KIND(value_node) != as_opt) &&
(N_KIND(value_node) != as_ivalue)) {
gen_s(I_PUSH_EFFECTIVE_ADDRESS, type_name);
gen_kic(I_ADD_IMMEDIATE, mu_word,
WORD_OFF(tt_access, collection_size), "collection size");
gen_value(value_node);
gen_kc(I_MOVE, mu_word, "update collection size");
gen_s(I_PUSH_EFFECTIVE_ADDRESS, type_name);
gen_kic(I_ADD_IMMEDIATE, mu_word,
WORD_OFF(tt_access, collection_avail), "collection avail");
gen_value(value_node);
gen_kc(I_MOVE, mu_word, "update collection avail");
}
break;
case(na_task_type_spec):
case(na_task_type):
entry_list = SIGNATURE(type_name);
priority = MAX_PRIO-2;
TYPE_KIND(type_name) = TK_WORD;/* SETL has '2' for this size */
TYPE_SIZE(type_name) = su_size(TK_WORD);
/* SETL has '2' for this size */
global_flag = TRUE;
offset = 0;
family_number = 0;
static_template = segment_new(SEGMENT_KIND_DATA, 4);
non_static_template = segment_new(SEGMENT_KIND_DATA, 4);
FORTUP(entry_node = (Node), entry_list, ft1);
if (N_KIND(entry_node) == as_line_no) {
;
}
else if (N_KIND(entry_node) == as_pragma) {
pragma_id = N_AST1(entry_node);
pragma_list = N_AST2(entry_node);
if (streq(N_VAL(pragma_id), "priority")) {
pragma_op = (Node) N_LIST(pragma_list)[1];
pragma_val = N_AST2(pragma_op);
priority = (int) N_VAL(pragma_val);
}
}
else {
family_number += 1;
name_node = N_AST1(entry_node);
entry_name = N_UNQ(name_node);
S_SEGMENT(entry_name) = 0;
S_OFFSET(entry_name) = family_number;
/* TBSL: do we need set TYPE_KIND here (think not) ds 8-14-85 */
TYPE_SIZE(entry_name) = size_entry(entry_name);
if (N_KIND(entry_node) == as_entry_family) {
entry_type = TYPE_OF(entry_name);
/* [[indx_type], -] := SIGNATURE(entry_type); */
tup = (Tuple) SIGNATURE(entry_type);
tup = (Tuple) tup[1];
indx_type = (Symbol) tup[1];
reference_of(indx_type);
global_flag &= is_static_type(indx_type);
if (global_flag) {
lng = length_of(indx_type);
low_node = (Node) SIGNATURE(indx_type)[2];
/* static_template
* +:= [offset-get_ivalue(low_node), lng];
*/
segment_put_word(static_template,
offset - get_ivalue_int(low_node));
segment_put_word(static_template, lng);
offset += lng;
}
/* non_static_template +:= ref; */
segment_put_word(non_static_template, REFERENCE_SEGMENT);
segment_put_word(non_static_template,
(int) REFERENCE_OFFSET);
}
else {
/* static_template +:= [offset, 1]; */
segment_put_word(static_template, offset);
segment_put_word(static_template, 1);
offset += 1;
/* non_static_template +:= [0, 0]; */
segment_put_word(non_static_template, 0);
segment_put_word(non_static_template, 0);
}
}
ENDFORTUP(ft1);
/* This may be a derived type */
parent_type = TYPE_OF(type_name);
task_proc = assoc_symbol_get(parent_type, TASK_INIT_PROC);
global_flag &= is_global(task_proc);
stemplate = template_new(TT_TASK, 1, WORDS_TASK, TT_PTR(&tt_task_ptr));
tt_task_ptr->priority = priority;
reference_of(task_proc);
tt_task_ptr->body_base = REFERENCE_SEGMENT;
tt_task_ptr->body_off = REFERENCE_OFFSET;
tt_task_ptr->nb_entries = offset;
tt_task_ptr->nb_families = family_number;
#ifdef MONITOR
#define NAMESIZE 119
{
int length;
static FILE *fp = NULL;
static char source_file[NAMESIZE];
if (strncmp( ORIG_NAME(type_name), "task_type:", 10 ))
{
length = strlen( ORIG_NAME(type_name));
strncpy( tt_task_ptr->task_name, ORIG_NAME(type_name),
length);
}
else
{
length = strchr( ORIG_NAME(type_name), 'n' )
- ORIG_NAME(type_name) - 10;
strncpy( tt_task_ptr->task_name,
ORIG_NAME(type_name)+10, length);
tt_task_ptr->task_name[length] = '\0';
}
if ( fp == NULL )
{
fp = fopen( "CWKLIB.$$$", "r" );
if ( fp == NULL )
{
fprintf(stderr, "Cannot open CWKLIB\n");
}
fgets( source_file, NAMESIZE, fp );
length = strlen(source_file) - 1;
source_file[length] = '\0';
}
strcpy(tt_task_ptr->task_file, source_file);
}
#undef NAMESIZE
#endif
repr_tup = REPR(type_name);
if (repr_tup == (Tuple)0) /* error condition */
value_node = OPT_NODE;
else
value_node = (Node) repr_tup[3];
if (N_KIND(value_node) == as_opt) {
tt_task_ptr->collection_size = ADA_MAX_INTEGER;
tt_task_ptr->collection_avail = ADA_MAX_INTEGER;
}
else if (N_KIND(value_node) == as_ivalue) {
collection_size = INTV((Const)N_VAL(value_node));
tt_task_ptr->collection_size = collection_size;
tt_task_ptr->collection_avail = collection_size;
}
if (global_flag) {
/* template +:= static_template; */
segment_append(stemplate, static_template);
}
else {
/* template +:= non_static_template; */
segment_append(stemplate, non_static_template);
/* TBSL: see if static_template and non_static template can be free
here */
}
install_type(type_name, stemplate, global_flag);
if ((N_KIND(value_node) != as_opt) &&
(N_KIND(value_node) != as_ivalue)) {
gen_s(I_PUSH_EFFECTIVE_ADDRESS, type_name);
gen_kic(I_ADD_IMMEDIATE, mu_word,
WORD_OFF(tt_task, collection_size), "collection size");
gen_value(value_node);
gen_kc(I_MOVE, mu_word, "update collection size");
gen_s(I_PUSH_EFFECTIVE_ADDRESS, type_name);
gen_kic(I_ADD_IMMEDIATE, mu_word,
WORD_OFF(tt_task, collection_avail), "collection avail");
gen_value(value_node);
gen_kc(I_MOVE, mu_word, "update collection avail");
}
break;
case(na_entry):
case(na_entry_former):
break;
default:
compiler_error_s("Unexpected type nature: ", type_name);
}
}
static void init_enum(Symbol type_name, Segment stemplate, int lbd, int ubd)
/*;init_enum*/
{
/* initialize enumeration map values in segment.
* the literal map is a tuple with pairs of values giving the string
* and the value. For C version we put values first, followed by length
* of string, followed by characters in string, one per word.
*/
Tuple litmap;
int i, n;
char *str;
int value, nstr;
/* enum_map := {[value, enum_lit]:
* [enum_lit, value] in OVERLOADS(type_name)};
* loop for value in [lbd..ubd] do
* template with:= #(enum_lit := enum_map(value));
* template +:= [ abs(charac): charac in enum_lit ];
* end loop for;
*/
litmap = (Tuple) literal_map(type_name);
n = tup_size(litmap);
for (value = lbd; value <= ubd; value++) {
/* find string for value */
str = (char *) 0;
for (i = 1; i <= n; i += 2) {
if ((int) litmap[i + 1] == value) {
str = litmap[i];
break;
}
}
if (str == (char *) 0) {
chaos("type.c: init_enum cannot find literal value");
}
nstr = strlen(str);
/* put string length */
segment_put_int(stemplate, nstr);
for (i = 0; i < nstr; i++) {
segment_put_int(stemplate, (int) str[i]);
}
}
}
/* Subtype elaboration */
void gen_subtype(Symbol type_name) /*;gen_subtype*/
{
/* This procedure processes subtypes only.
* Note: all access subtypes have been changed to derived types by expander.
*/
int type_install_done;
int global_flag, i, nelts;
Node l_node, u_node, d_node, s_node, parent_l_node, parent_u_node;
Tuple type_list, index_list, discr_list, constraint, tup, sig;
int nb_dim, l, inum2, inum5, iden2, iden5;
long nb_elements, nb_len; /* long to avoid overflow problems */
Symbol type_mark, comp_type, index, typ, indx_type, b_index;
Symbol temp_name, field_name, temp_var, sym , x;
Fortup ft1;
Node low, high, b_low, b_high, dgt_node, lbd_node;
Node ubd_node, dlt_node, sml_node;
int static_qual, static_check;
Tuple base_index_list, field_map;
Const plow, phigh, lw_val, hg_val, b_lw_val, b_hg_val, consT;
int lw_vali, hg_vali, b_lw_vali, b_hg_vali;
int low_int, high_int, val_low = 0, val_high = 0, val_defined = 0;
float low_float, high_float;
Const low_const, high_const, small_const;
Rational rat;
int *num1, *den1, *num2, *den2;
Const parent_low_const, parent_high_const;
Segment stemplate;
struct tt_array *tt_array_ptr;
struct tt_s_array *tt_s_array_ptr;
struct tt_e_range *tt_e_range_ptr;
struct tt_i_range *tt_i_range_ptr;
struct tt_fl_range *tt_fl_range_ptr;
struct tt_fx_range *tt_fx_range_ptr;
struct tt_c_record *tt_c_record_ptr;
#ifdef TRACE
if (debug_flag)
gen_trace_symbol("GEN_SUBTYPE", type_name);
#endif
type_mark = TYPE_OF(type_name);
constraint = get_constraint(type_name);
switch((int) constraint[1]) {
case(co_access):
if ((int) CONTAINS_TASK((Symbol) designated_type(type_name))) {
assign_same_reference(type_name, type_mark);
TYPE_KIND(type_name) = TYPE_KIND(type_mark);
TYPE_SIZE(type_name) = TYPE_SIZE(type_mark);
}
else {
assign_same_reference(type_name, symbol_daccess);
TYPE_KIND(type_name) = TYPE_KIND(symbol_daccess);
TYPE_SIZE(type_name) = TYPE_SIZE(symbol_daccess);
}
break;
case(co_index):
sig = SIGNATURE(type_name);
index_list = (Tuple) sig[1];
comp_type = (Symbol) sig[2];
nb_dim = tup_size(index_list);
nb_elements = 1;
FORTUP(index = (Symbol), index_list, ft1);
l = length_of(index);
if (l >= 0)
nb_elements *= l;
else
nb_elements = -1;
ENDFORTUP(ft1);
if (nb_elements >= 0 && has_static_size(comp_type)) {
/* This is a kludge, needed for c43206a (shields 7-8-86) */
nb_len = nb_elements * TYPE_SIZE(comp_type);
if (nb_len > MAX_STATIC_SIZE)
nb_len = -1;
TYPE_SIZE(type_name) = nb_len;
}
else {
TYPE_SIZE(type_name) = -1;/* SETL uses -1 here */
}
stemplate = template_new(TT_C_ARRAY, size_of(type_name),
WORDS_ARRAY, TT_PTR(&tt_array_ptr));
tt_array_ptr->dim = nb_dim;
global_flag = has_static_size(type_name);
type_list = tup_copy(index_list);
type_list = tup_with(type_list, (char *) comp_type);
/* The first two items retrieved correspond to the component
* type and first index type, respectively. These are stored
* in the fixed part of the template; further items (if any)
* follow this fixed part.
*/
nelts = 0;
while (tup_size(type_list)) {
typ = (Symbol) tup_frome(type_list);
reference_of(typ);
global_flag &= is_global(typ);
if (nelts == 0) { /* if component type */
tt_array_ptr->component_base = REFERENCE_SEGMENT;
tt_array_ptr->component_offset = REFERENCE_OFFSET;
nelts++;
}
else if (nelts == 1) { /* if first index type */
tt_array_ptr->index1_base = REFERENCE_SEGMENT;
tt_array_ptr->index1_offset = REFERENCE_OFFSET;
nelts++;
}
else {
segment_put_int(stemplate, REFERENCE_SEGMENT);
segment_put_int(stemplate, (int) REFERENCE_OFFSET);
}
}
tup_free(type_list);
if ((nb_dim == 1) && global_flag) {
indx_type = (Symbol) index_list[1];
tup = SIGNATURE(indx_type);
low = (Node) tup[2];
high = (Node) tup[3];
stemplate = template_new(TT_S_ARRAY, size_of(type_name),
WORDS_S_ARRAY, TT_PTR(&tt_s_array_ptr));
tt_s_array_ptr->component_size = size_of(comp_type);
tt_s_array_ptr->index_size = size_of(indx_type);
/* TBSL: check bounds are integers, assume so for now */
low_const = get_ivalue(low);
if (low_const->const_kind == CONST_INT)
low_int = low_const->const_value.const_int;
else
chaos("low bound not int");
high_const = get_ivalue(high);
if (high_const->const_kind == CONST_INT)
high_int = high_const->const_value.const_int;
else
chaos("high bound not int");
tt_s_array_ptr->salow = low_int;
tt_s_array_ptr->sahigh = high_int;
}
static_qual = TRUE;
base_index_list = INDEX_TYPES(base_type(type_name));
base_index_list = tup_copy(base_index_list);
FORTUP(index = (Symbol), index_list, ft1);
b_index = (Symbol) tup_fromb(base_index_list);
tup = SIGNATURE(index);
low = (Node) tup[2];
high = (Node) tup[3];
tup = SIGNATURE(b_index);
b_low = (Node) tup[2];
b_high = (Node) tup[3];
lw_val = get_ivalue(low);
hg_val = get_ivalue(high);
b_lw_val = get_ivalue(b_low);
b_hg_val = get_ivalue(b_high);
if ( lw_val->const_kind == CONST_OM
|| hg_val->const_kind == CONST_OM
|| b_lw_val->const_kind == CONST_OM
|| b_hg_val->const_kind == CONST_OM) {
static_qual = FALSE;
break;
}
/* TBSL:check that values are in fact integers */
else {
lw_vali = lw_val->const_value.const_int;
hg_vali = hg_val->const_value.const_int;
b_lw_vali = b_lw_val->const_value.const_int;
b_hg_vali = b_hg_val->const_value.const_int;
if (lw_vali <= hg_vali &&/* No check on null ranges */
(lw_vali < b_lw_vali || hg_vali > b_hg_vali)) {
/* Raise CONSTRAINT_ERROR */
gen_s(I_LOAD_EXCEPTION_REGISTER, symbol_constraint_error);
gen(I_RAISE);
break;
}
}
ENDFORTUP(ft1);
install_type(type_name, stemplate, global_flag);
if (!static_qual) {
gen_s(I_PUSH_EFFECTIVE_ADDRESS, type_name);
gen_s(I_QUAL_SUB, base_type(type_name));
gen_ks(I_DISCARD_ADDR, 1, type_name);
}
break;
case(co_range):
/* The SETL version builds range part of template and then puts it
* in the proper place in the final template. In C we set the
* desired values in val_low and val_high.
*/
val_defined = FALSE;
l_node = (Node) constraint[2];
u_node = (Node) constraint[3];
tup = SIGNATURE(type_mark);
parent_l_node = (Node) tup[2];
parent_u_node = (Node) tup[3];
parent_low_const = get_ivalue(parent_l_node);
parent_high_const = get_ivalue(parent_u_node);
low_const = get_ivalue(l_node);
high_const = get_ivalue(u_node);
if (low_const->const_kind != CONST_OM
&& high_const->const_kind != CONST_OM
&& parent_low_const->const_kind != CONST_OM
&& parent_high_const->const_kind != CONST_OM) {
/* static range */
static_check = TRUE;
global_flag = TRUE;
if ( const_gt(low_const, high_const)/* null range */
||(const_ge(low_const, parent_low_const)
&& const_le(high_const, parent_high_const))) {
/* template := [val_low, val_high]; */
val_defined = TRUE;
val_low = get_const_int(low_const);
val_high = get_const_int(high_const);
}
else {
gen_s(I_LOAD_EXCEPTION_REGISTER, symbol_constraint_error);
gen(I_RAISE);
/* template := [val_low, val_high]; */
val_defined = TRUE;
val_low = get_const_int(low_const);
val_high = get_const_int(high_const);
}
}
else {
gen_value(l_node);
gen_value(u_node);
if (base_type(type_mark) == type_mark) {
/* Subtype of the base type, no check needed */
static_check = TRUE;
}
else {
static_check = FALSE;
}
global_flag = FALSE;
/* TBSL: see if int_const is proper for all types if parent_ not
* defined ds 8-1-85
*/
/* template := [parent_low ? 0, parent_high ? 0]; */
if (parent_low_const->const_kind != CONST_OM) {
val_defined = TRUE;
val_low = get_const_int(parent_low_const);
}
else {
val_defined = TRUE;
val_low = 0;
}
if (parent_high_const->const_kind != CONST_OM) {
val_defined = TRUE;
val_high = get_const_int(parent_high_const);
}
else {
val_defined = TRUE;
val_high = 0;
}
}
TYPE_KIND(type_name) = TYPE_KIND(type_mark);
TYPE_SIZE(type_name) = TYPE_SIZE(type_mark);
if (is_enumeration_type(type_name)) {
/* SETL code builds trailing part then puts standard header at front
* In C, we have set val_defined if there are values to insert
* and have the values in val_low and val_high, respectively.
*/
/* template := [TT_E_RANGE, size_of(type_mark)] + template */
stemplate = template_new(TT_E_RANGE, size_of(type_mark),
WORDS_E_RANGE, TT_PTR(&tt_e_range_ptr));
if (val_defined) {
tt_e_range_ptr->elow = val_low;
tt_e_range_ptr->ehigh = val_high;
}
reference_of(root_type(type_mark));
tt_e_range_ptr->ebase = REFERENCE_SEGMENT;
tt_e_range_ptr->eoff = REFERENCE_OFFSET;
}
else {
/* TBSL: need re adjust type to i_range_l if long, etc */
/* template := [TT_I_RANGE, size_of(type_mark)]+template; */
stemplate = template_new(TT_I_RANGE, size_of(type_mark),
WORDS_I_RANGE, TT_PTR(&tt_i_range_ptr));
tt_i_range_ptr->ilow = val_low;
tt_i_range_ptr->ihigh = val_high;
}
/* This is more or less equivalent to INSTALL_TYPE: */
if (global_flag) { /* static type */
assign_same_reference(type_name, get_constant_name(stemplate));
}
else {
if (CURRENT_LEVEL == 1) {/* non-static, global */
next_global_reference_template(type_name, stemplate);
gen_s(I_TYPE_GLOBAL, type_name);
}
else {
next_local_reference(type_name);
temp_name = new_unique_name("type_template");
assign_same_reference(temp_name, get_constant_name(stemplate));
gen_s(I_TYPE_LOCAL, temp_name);
gen_s(I_UPDATE_AND_DISCARD, type_name);
}
}
if (!static_check) {
gen_s(I_PUSH_EFFECTIVE_ADDRESS, type_name);
gen_s(I_QUAL_SUB, type_mark);
gen_ks(I_DISCARD_ADDR, 1, type_name);
}
break;
case(co_digits):
l_node = (Node) constraint[2];
u_node = (Node) constraint[3];
d_node = (Node) constraint[4];
tup = get_constraint(TYPE_OF(type_name));
lbd_node = (Node) tup[2];
ubd_node = (Node) tup[3];
dgt_node = (Node) tup[4];
if (const_gt(get_ivalue(d_node), get_ivalue(dgt_node))) {
gen_s(I_LOAD_EXCEPTION_REGISTER, symbol_constraint_error);
gen(I_RAISE);
}
low_const = get_ivalue(l_node);
high_const = get_ivalue(u_node);
if (low_const->const_kind != CONST_OM
&& high_const->const_kind != CONST_OM) {
plow = get_ivalue(lbd_node);
phigh = get_ivalue(ubd_node);
if (plow->const_kind != CONST_OM && phigh->const_kind != CONST_OM) {
if (const_lt(low_const, high_const)
&& (const_lt(low_const, plow) || const_gt(high_const,phigh))){
gen_s(I_LOAD_EXCEPTION_REGISTER, symbol_constraint_error);
gen(I_RAISE);
}
}
global_flag = TRUE;
/* template := [low, high]; */
low_float = REALV(low_const);
high_float = REALV(high_const);
}
else {
gen_value(l_node);
gen_value(u_node);
global_flag = FALSE;
low_float = 0.0;
high_float = 0.0;
/* template := [0, 0]; */
}
TYPE_KIND(type_name) = TYPE_KIND(type_mark);
TYPE_SIZE(type_name) = TYPE_SIZE(type_mark);
/* template := [TT_F_RANGE, size_of(type_mark)] + template; */
#ifdef TBSL
-review carefully the setting of template here
#endif
stemplate = template_new(TT_FL_RANGE, size_of(type_mark),
WORDS_FL_RANGE, TT_PTR(&tt_fl_range_ptr));
tt_fl_range_ptr->fllow = low_float;
tt_fl_range_ptr->flhigh = high_float;
install_type(type_name, stemplate, global_flag);
break;
case(co_delta):
#ifdef TBSL
-- review template initialization. Note that low and high as et
-- in template must be longs.
#endif
l_node = (Node) constraint[2];
u_node = (Node) constraint[3];
d_node = (Node) constraint[4];
s_node = (Node) constraint[5];
constraint = get_constraint(TYPE_OF(type_name));
lbd_node = (Node) constraint[2];
ubd_node = (Node) constraint[3];
dlt_node = (Node) constraint[4];
sml_node = (Node) constraint[5];
consT = get_ivalue(d_node);
if (consT->const_kind != CONST_RAT)
chaos("arg not rational");
rat = consT->const_value.const_rat;
num1 = num(rat);
den1 = den(rat);
consT = get_ivalue(dlt_node);
/* [num2, den2] := get_ivalue(dlt_node); */
if (consT->const_kind != CONST_RAT)
chaos("arg not rational");
rat = consT->const_value.const_rat;
num2 = num(rat);
den2 = den(rat);
if (int_lss(int_mul(num1, den2), int_mul(num2, den1))) {
gen_s(I_LOAD_EXCEPTION_REGISTER, symbol_constraint_error);
gen(I_RAISE);
}
/* The subtype uses the same run-time representation as the type
* so we place in the template the 'small of the type.
*/
small_const = get_ivalue(sml_node);
split_powers(num(RATV(small_const)));
inum2 = split_powers_2;
inum5 = split_powers_5;
split_powers(den(RATV(small_const)));
iden2 = split_powers_2;
iden5 = split_powers_5;
/* template := [TT_FIXED, size_of(type_mark), num2-den2, num5-den5]; */
stemplate = template_new(TT_FX_RANGE, size_of(type_mark),
WORDS_FX_RANGE, TT_PTR(&tt_fx_range_ptr));
tt_fx_range_ptr->small_exp_2 = inum2 - iden2;
tt_fx_range_ptr->small_exp_5 = inum5 - iden5;
/* TBSL: may want to force size to 4 here */
root_type(type_name) = root_type(base_type(type_name));
low_const = get_ivalue(l_node);
high_const = get_ivalue(u_node);
if (low_const->const_kind != CONST_OM
&& high_const->const_kind != CONST_OM) {
plow = get_ivalue(lbd_node);
phigh = get_ivalue(ubd_node);
if (plow->const_kind != CONST_OM && phigh->const_kind != CONST_OM) {
if (int_lss(int_mul(num(RATV(low_const)),den(RATV(high_const))),
int_mul(num(RATV(high_const)), den(RATV(low_const))))
&& (int_lss(int_mul(num(RATV(low_const)), den(RATV(plow))),
int_mul(num(RATV(plow)), den(RATV(low_const))))
|| int_gtr(int_mul(num(RATV(high_const)), den(RATV(phigh))),
int_mul(num(RATV(phigh)), den(RATV(high_const)))))) {
gen_s(I_LOAD_EXCEPTION_REGISTER, symbol_constraint_error);
gen(I_RAISE);
}
}
global_flag = TRUE;
tt_fx_range_ptr->fxlow = rat_tof(low_const, small_const, 1);
tt_fx_range_ptr->fxhigh = rat_tof(high_const, small_const, 1);
TYPE_KIND(type_name) = TK_LONG;
TYPE_SIZE(type_name) = su_size(TK_LONG);
}
else {
global_flag = FALSE;
segment_put_int(stemplate, 0);
segment_put_int(stemplate, 0);
/* template +:= if template(1+TT_OBJECT_SIZE) = 1 then [0, 0] *
else [0, 0, 0, 0] * end; */
gen_value(l_node);
gen_s(I_QUAL_RANGE, type_mark);
gen_value(u_node);
gen_s(I_QUAL_RANGE, type_mark);
}
install_type(type_name, stemplate, global_flag);
break;
case(co_discr):
type_install_done = FALSE;
type_mark = base_type(type_mark);
field_map = (Tuple) constraint[2];
stemplate = template_new(TT_C_RECORD, size_of(type_mark),
WORDS_C_RECORD, TT_PTR(&tt_c_record_ptr));
reference_of(type_mark);
tt_c_record_ptr->cbase = REFERENCE_SEGMENT;
tt_c_record_ptr->coff = REFERENCE_OFFSET;
/* TBSL: Adjust type_size if no default values for discriminants */
TYPE_KIND(type_name) = TT_C_RECORD;
TYPE_SIZE(type_name) = TYPE_SIZE(type_mark);
/* obtain discriminants in same order as in unconstrained type */
tup = SIGNATURE(type_mark);
/* need tup_copy for discr_list since used in tup_frome below */
discr_list = tup_copy((Tuple) tup[3]);
tt_c_record_ptr->nb_discr_c = tup_size(discr_list);
if (tup_size(field_map) == 0) {
/* Special case: vals of discriminants fetched from record object */
/* already on TOS. */
global_flag = FALSE;
for (i = 1; i <= tup_size(discr_list); i++) {
segment_put_int(stemplate, 0);
}
/* template +:= [0: x in discr_list]; */
temp_var = new_unique_name("temporary");
next_local_reference(temp_var);
gen_s(I_UPDATE, temp_var);
while (tup_size(discr_list) != 0) {
field_name = (Symbol) tup_frome(discr_list);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, temp_var);
/* SETL has field_name as last argument, presumably as part of
* comment part of instruction and not part of generated code
* ds 7-5-85
*/
/* gen_ki(I_ADD_IMMEDIATE, mu_word, *
* field_offset(field_name)(TARGET), field_name);
*/
gen_ki(I_ADD_IMMEDIATE, mu_word, FIELD_OFFSET(field_name));
gen_k(I_DEREF, kind_of(TYPE_OF(field_name)));
}
}
else {
/* global_flag = is_global(type_mark) and
* (forall x in
* discr_list | is_ivalue(field_map(x)));
*/
global_flag = is_global(type_mark) && (TYPE_SIZE(type_mark) != -1);
FORTUP(x = (Symbol), discr_list, ft1);
if (!is_ivalue(discr_map_get(field_map, x))) {
global_flag = FALSE;
break;
}
ENDFORTUP(ft1);
if (global_flag) {
/* template +:= [get_ivalue(field_map(x)):x in discr_list]; */
FORTUP(sym = (Symbol), discr_list, ft1);
segment_put_const(stemplate,
get_ivalue(discr_map_get(field_map, sym)));
ENDFORTUP(ft1);
}
else {
/* template +:= [0: x in discr_list]; */
for (i = 1; i <= tup_size(discr_list); i++) {
segment_put_int(stemplate, 0);
}
/* if there is a TT_D_ARRAY or a TT_D_RECORD containing
* a TT_D_ARRAY, a check is made so that the discriminant
* belongs to the index subtype of the array.
*/
while (tup_size(discr_list) != 0) {
field_name = (Symbol) tup_frome(discr_list);
d_node = (discr_map_get(field_map, field_name));
gen_value(d_node);
gen_s (I_QUAL_RANGE, TYPE_OF (field_name));
}
install_type(type_name, stemplate, global_flag);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, type_name);
gen (I_CHECK_REC_SUBTYPE);
type_install_done = TRUE;
}
}
if (! type_install_done) {
install_type(type_name, stemplate, global_flag);
}
break;
default:
compiler_error_c("Unexpected subtype constraint: ", constraint);
}
}
static void install_type(Symbol type_name, Segment stemplate, int global_flag)
/*;install_type*/
{
Symbol temp_name;
if (global_flag) { /* static type */
assign_same_reference(type_name, get_constant_name(stemplate));
}
else if (CURRENT_LEVEL == 1) {/* non-static, global */
next_global_reference_template(type_name, stemplate);
gen_s(I_TYPE_GLOBAL, type_name);
}
else { /* non-static, local */
next_local_reference(type_name);
temp_name = new_unique_name("type_template");
assign_same_reference(temp_name, get_constant_name(stemplate));
gen_s(I_TYPE_LOCAL, temp_name);
gen_s(I_UPDATE_AND_DISCARD, type_name);
}
/* free template - this is final use*/
segment_free(stemplate);
}
static Segment make_fixed_template(Const old_lbd, Const old_ubd,
Const old_delta, Const old_small_arg, struct tt_fx_range **ptr)
/*;make_fixed_template*/
{
/*DESCR: Elaborates the template from the front end's fixed point ITYPE.
*INPUT: old_itype: Fixed Point ITYPE from ADASEM.(with added
* small field for the new length clause. This
* field will be OM unless small has been set by
* length clause.
*OUTPUT: Returns template: Fixed point type template.
*/
int small_exp_2, /* parameters of new type template */
small_exp_5, size;
int bits;
int power_conv; /* set when cannot convert small representation */
long new_lbd, new_ubd;
int num_2, num_5, num_other, /* powers of numerator */
den_2, den_5, den_other;/* powers of denominator */
Segment stemplate;
Const old_small; /* need to copy arg since value changed */
struct tt_fx_range *tt_fx_range_ptr;
old_small = rat_const(RATV(old_small_arg));
/* find SMALL exponents */
split_powers(num(RATV(old_small)));
num_2 = split_powers_2;
num_5 = split_powers_5;
num_other = split_powers_value;
/* [den_2, den_5, den_other] := split_powers(den(old_small)); */
split_powers(den(RATV(old_small)));
den_2 = split_powers_2;
den_5 = split_powers_5;
den_other = split_powers_value;
if (num_other != den_other) {/* small not allowed */
user_error("Small not supported by implementation.(Appendix F)");
power_conv = power_of_2(old_delta);
if (power_conv) {
user_error(
"Precision not supported by implementation. (Appendix F)");
}
small_exp_2 = power_of_2_power;
small_exp_5 = 0;
RATV(old_small) = power_of_2_small;
}
else {
small_exp_2 = num_2 - den_2;
small_exp_5 = num_5 - den_5;
}
#ifdef TBSL
if (ABS(small_exp_2) > 30 || ABS(small_exp_5) > 9) {
-- check that 1/MAX_INT < old_small < MAX_INT
SIGN(small_exp_2) == SIGN(small_exp_5) &&
5**(iabs( small_exp_5)) * 2**(iabs( small_exp_2)) > MAX_INT ) {
user_error(PRECISION_NOT_SUPPORTED);
}
#endif
bits = fx_mantissa(RATV(old_lbd), RATV(old_ubd), RATV(old_small))+1;
/* +1 for sign*/
if (bits > WORD_SIZE) {
user_error(PRECISION_NOT_SUPPORTED);
}
size = su_size(TK_LONG); /* FORCE this for initial C version ds 6-6-85
*/
new_lbd = rat_tof(old_lbd, old_small, size);
new_ubd = rat_tof(old_ubd, old_small, size);
/* return [TT_FIXED, size, small_exp_2, small_exp_5]+new_lbd+new_ubd; */
stemplate = template_new(TT_FX_RANGE, size, WORDS_FX_RANGE,
TT_PTR(&tt_fx_range_ptr));
tt_fx_range_ptr->small_exp_2 = small_exp_2;
tt_fx_range_ptr->small_exp_5 = small_exp_5;
tt_fx_range_ptr->fxlow = new_lbd;
tt_fx_range_ptr->fxhigh = new_ubd;
*ptr = tt_fx_range_ptr;
return (stemplate);
}
static void split_powers(int *avalue) /*;split_powers*/
{
/*DESCR: This procedure splits value into a power of 5, a power of 2
* and the remaining factors.
*INPUT: value: integer.
*OUTPUT: [pow_2 pow_5 others] such that
* value= 2**pow_2 * 5**pow_5 * others
*/
/* The C version does not return a tuple, but sets the variables
* split_powers_2, split_powers_5 and split_powers_value global
* to this module
*/
int pow_2, /* desired power of 2 */
pow_5; /* desired power of 5 */
int *int_2, *int_5;
int *v;
pow_2 = 0;
pow_5 = 0;
int_2 = int_fri(2); /* should be global */
int_5 = int_fri(5);
v = int_copy(avalue);
while((v[v[0]] % 2 ) == 0 && v[0] > 0) {
v = int_quo(v, int_2);
pow_2 += 1;
}
while((v[v[0]] % 5 ) == 0 && v[0] > 0) {
v = int_quo(v, int_5);
pow_5 += 1;
}
/* return [pow_2, pow_5, value]; */
split_powers_2 = pow_2;
split_powers_5 = pow_5;
split_powers_value = int_toi(v);
}
long rat_tof(Const value, Const small, int size) /*;rat_tof*/
{
/* DESCR: This procedure converts a rational number into a fixed
* point number with the given small and size.
* INPUT: value: [num den], A rational number(see RATIONAL
* ARITHMETIC PACKAGE).
* small: the given small as a rational number
* size: 1 or 2, size(in words or tuples) for the result
* OUTPUT: [N] N being one or two integers(depending on size)
*/
long N; /* intermediate value */
/* for first C version, use rat_tol which returns long. SETL uses rat_toi.*/
/* force size to be 1 for initial C version */
size = 1;
if (value->const_kind != CONST_RAT || small->const_kind != CONST_RAT) {
#ifdef DEBUG
zpcon(value);
zpcon(small);
#endif
chaos("rat_tof arguments not rationals");
}
N = rat_tol(rat_div(RATV(value), RATV(small)));
if (size == 1) {
#ifdef TBSN
-- ignore overflow:
if called by make_fixed_template message already
-- emitted. In case of expression or initial value should be OK
-- (as long as they belong to the type)
if (arith_overflow) {
compiler_error("Value too big");
}
#endif
return N;
}
#ifdef TBSN
-- do this when have multiple fixed types
$will work anyway...
else
if N >= 0 then
if N > MAX_INT*(MAX_UNS+1)+MAX_UNS then
compiler_error("Value too big");
end if;
RAT_TO_F_1 = N div (MAX_UNS+1);
RAT_TO_F_2 = N mod (MAX_UNS+1);
return;
else
if N < MIN_INT*(MAX_UNS+1) then
compiler_error("Value too big");
end if;
RAT_TOF_1 = (N-MAX_UNS) div (MAX_UNS+1);
RAT_TOF_2 = N mod (MAX_UNS+1);
return;
end if;
end if;
#endif
}
static void process_record(Symbol type_name) /*;process_record*/
{
Tuple repr_tup, tup, type_list, discr_decl, fixed_part, dep_types;
Node invariant_node, variant_node, node, id_list_node, n, d;
Node subtype_node, id_node, type_node;
Fortup ft1, ft2;
int i, varying_size_flag, type_class, discr_with_defaults;
Symbol subtype_name, t_name, discr, some_discr_name;
Tuple discr_subtypes;
Segment stemplate;
struct tt_u_record *tt_u_record_ptr;
#ifdef TRACE
if (debug_flag )
gen_trace_symbol("PROCESS_RECORD", type_name);
#endif
segment_empty(VARIANT_TABLE);
CURRENT_FIELD_NUMBER = 0;
CURRENT_FIELD_OFFSET = 0;
segment_empty(FIELD_TABLE);
INTERNAL_ACCESSED_TYPES = tup_new(0);
STATIC_REC = TRUE; /* just an assumption... */
tup = SIGNATURE(type_name);
/* [[invariant_node, variant_node], discr_decl] := SIGNATURE(type_name); */
/* recall that signature is 5-tuple in C version */
invariant_node = (Node) tup[1];
variant_node = (Node) tup[2];
discr_decl = (Tuple) tup[3];
type_list = tup_new(0);
fixed_part = tup_new(0);
FORTUP(node = (Node), N_LIST(invariant_node), ft1);
switch(N_KIND(node)) {
case(as_field):
id_list_node = N_AST1(node);
FORTUP(n = (Node), N_LIST(id_list_node), ft2);
fixed_part = tup_with(fixed_part, (char *) N_UNQ(n));
ENDFORTUP(ft2);
/* fixed_part +:= [N_UNQ(n) : n in N_LIST(id_list_node)]; */
break;
case(as_subtype_decl):
type_list = tup_with(type_list, (char *) node);
break;
case(as_deleted):
break;
default:
compiler_error_k("Unexpected kind of selector in record: ",
node);
}
ENDFORTUP(ft1);
/* then, are there discriminants ? */
if (tup_size(discr_decl) != 0) {
linearize_record(discr_decl, OPT_NODE);
/* discriminant dependent subtypes: elaborate and check if varying sz */
/* dep_types := [discr_dep_subtype(d):d in type_list]; */
dep_types = tup_new(tup_size(type_list));
FORTUPI(d = (Node), type_list, i, ft1);
dep_types[i] = (char *) discr_dep_subtype(d);
ENDFORTUP(ft1);
varying_size_flag = FALSE;
for (i = 1; i <= tup_size(type_list); i++) {
subtype_node = (Node) type_list[i];
id_node = N_AST1(subtype_node);
subtype_name = N_UNQ(id_node);
/* An anonymous subtype used by a constrained access subtype
* indication, that refers to discriminants, does not make the
* record of variable size....
*/
if (dep_types[i] && !tup_mem((char *) subtype_name,
INTERNAL_ACCESSED_TYPES)) {
varying_size_flag = TRUE;
break;
}
}
/* class of type: */
some_discr_name = (Symbol) discr_decl[tup_size(discr_decl)];
discr_with_defaults = (Node) default_expr(some_discr_name) != OPT_NODE;
if (discr_with_defaults) {
type_class = TT_U_RECORD;
TYPE_KIND(type_name) = TT_U_RECORD;
/* discr_subtypes := [ TYPE_OF(discr) : discr in discr_decl]; */
discr_subtypes = tup_new(tup_size(discr_decl));
FORTUPI(discr = (Symbol), discr_decl, i, ft1);
discr_subtypes[i] = (char *) TYPE_OF(discr);
ENDFORTUP(ft1);
/* loop forall i in [1..#type_list] | dep_types(i) do */
for (i = 1; i <= tup_size(type_list); i++) {
if (dep_types[i]) {
id_node = N_AST1((Node) type_list[i]);
eval_max_size(N_UNQ(id_node), discr_subtypes);
}
}
}
else if (varying_size_flag) {
TYPE_KIND(type_name) = TT_V_RECORD;
type_class = TT_V_RECORD;
}
else {
TYPE_KIND(type_name) = TT_U_RECORD;
type_class = TT_U_RECORD;
}
stemplate = template_new(type_class, 0, WORDS_U_RECORD,
TT_PTR(&tt_u_record_ptr));
tt_u_record_ptr->nb_field_u = 0; /* nb_fields */
tt_u_record_ptr->nb_discr_u = tup_size(discr_decl); /* nb_discr */
tt_u_record_ptr->nb_fixed_u =
tup_size(discr_decl) + tup_size(fixed_part); /* nb_fixed */
/* set first entry in field_table after end of fixed part of template */
tt_u_record_ptr->first_case = linearize_record(fixed_part,variant_node);
/* size of variant table */
tt_u_record_ptr->variant = segment_get_maxpos(VARIANT_TABLE);
}
else {
FORTUP(type_node = (Node), type_list, ft1);/* Elaborate types */
id_node = N_AST1(type_node);
t_name = N_UNQ(id_node);
gen_subtype(t_name);
ENDFORTUP(ft1);
TYPE_KIND(type_name) = TT_RECORD;
type_class = TT_RECORD;
stemplate = template_new(TT_RECORD, 0, WORDS_RECORD,
TT_PTR(&tt_u_record_ptr));
linearize_record(fixed_part, OPT_NODE);
}
if (type_class == TT_V_RECORD) {
TYPE_SIZE(type_name) = -1;/* TBSL: SETL uses -1 here */
}
else {
TYPE_SIZE(type_name) = CURRENT_FIELD_OFFSET;
}
tt_u_record_ptr->object_size = size_of(type_name);
repr_tup = REPR(type_name);
if (repr_tup != (Tuple)0) {
tt_u_record_ptr->repr_size = (int) repr_tup[2];
}
else {
tt_u_record_ptr->repr_size = 0;
}
/* template may also be tt_record case, but no harm since
* nb_field_u at same offset as nb_field
*/
tt_u_record_ptr->nb_field_u = CURRENT_FIELD_NUMBER;
/* template +:= FIELD_TABLE+VARIANT_TABLE; */
segment_append(stemplate, FIELD_TABLE);
segment_append(stemplate, VARIANT_TABLE);
install_type(type_name, stemplate, STATIC_REC);
}
static int linearize_record(Tuple fixed_part_list, Node variant_part_node)
/*;linearize_record*/
{
/* process fixed part
* For each record comp in fixed part, add three entries to FIELD_TABLE:
* offset, base of template for comp, segment of template for component.
*/
Symbol f_name, f_type, name;
Fortup ft1, ft2;
int tsize, first_field, v_index, index;
Node variant_node, name_node, others_body, alt_node;
Node f_node, v_node, id_list_node, node, n_sym;
int save_field_offset, max_field_offset, variant_offset;
Tuple bodies, f_part, ntable, tup4, table, tup;
Tuple case_range;
int i, n, b;
#ifdef TRACE
if (debug_flag) {
gen_trace_symbols("LINEARIZE_RECORD_F", fixed_part_list);
gen_trace_node("LINEARIZE_RECORD_V", variant_part_node);
}
#endif
FORTUP(f_name = (Symbol), fixed_part_list, ft1);
f_type = TYPE_OF(f_name);
FIELD_NUMBER(f_name) = (char *) CURRENT_FIELD_NUMBER;
CURRENT_FIELD_NUMBER += 1;
FIELD_OFFSET(f_name) = CURRENT_FIELD_OFFSET;
/* FIELD_TABLE +:= [CURRENT_FIELD_OFFSET] + * reference_of(f_type); */
segment_put_word(FIELD_TABLE, CURRENT_FIELD_OFFSET);
reference_of(f_type);
segment_put_int(FIELD_TABLE, REFERENCE_SEGMENT);
segment_put_int(FIELD_TABLE, REFERENCE_OFFSET);
/* STATIC_REC and:= is_static_type(f_type); */
STATIC_REC = STATIC_REC ? is_static_type(f_type) : FALSE;
if (CURRENT_FIELD_OFFSET != -1) {
tsize = TYPE_SIZE(f_type);
if (tsize >= 0 && CURRENT_FIELD_OFFSET >= 0) {
CURRENT_FIELD_OFFSET += tsize;
}
else {
CURRENT_FIELD_OFFSET = -1;
}
}
ENDFORTUP(ft1);
if (variant_part_node != OPT_NODE) {
name_node = N_AST1(variant_part_node);
variant_node = N_AST2(variant_part_node);
name = N_UNQ(name_node);
/*-- bodies is used in tup_from? below: see if tup_copy needed here
*- ds 6-25-85
*/
tup = make_case_table(variant_node);
table = (Tuple) tup[1];
bodies = (Tuple) tup[2];
bodies = tup_copy(bodies);/* to be safe - see above comment */
others_body = (Node) tup[3];
tup_free(tup);
/* [table, bodies, others_body] := make_case_table(variant_node); */
n = tup_size(table);
table = tup_exp(table, n + 1);
for (i = n; i > 0; i--)
table[i + 1] = table[i];
tup = tup_new(2);
tup[1] = (char *)(n + 1);
tup[2] = (char *) 0;
table[1] = (char *) tup;
ntable = tup_new(n+1);
/* table := [ [#table+1, 0] ] + table; */
if (others_body != OPT_NODE) {
index = 0;
/* bodies := [others_body]+bodies; */
n = tup_size(bodies);
bodies = tup_exp(bodies, n + 1);
for (i = n; i > 0; i--)
bodies[i + 1] = bodies[i];
bodies[1] = (char *) others_body;
}
else {
index = 1;
/* The SETL version mixes quadruples and pairs in the tuple
* table. Here we keep all quadruples in another tuple ntable;
* table := * [ [a, if b = 0 then [0, -1, -1] else b end]: [a, b]
* in table ];
*/
FORTUPI(tup = (Tuple), table, i, ft1);
b = (int) tup[2];
if (b == 0) {
tup4 = tup_new(4);
tup4[1] = tup[1];
tup4[2] = (char *) 0;
tup4[3] = (char *) - 1;
tup4[4] = (char *) - 1;
ntable[i] = (char *) tup4;
}
ENDFORTUP(ft1);
}
/* to allow overlapping of variants: */
save_field_offset = max_field_offset = CURRENT_FIELD_OFFSET;
/* process each variant */
while(tup_size(bodies) != 0) {
CURRENT_FIELD_OFFSET = save_field_offset;
first_field = CURRENT_FIELD_NUMBER;
alt_node = (Node) tup_fromb(bodies);
f_node = N_AST1(alt_node);
v_node = N_AST2(alt_node);
f_part = tup_new(0);
FORTUP(node = (Node), N_LIST(f_node), ft1);
id_list_node = N_AST1(node);
/* f_part +:= [ N_UNQ(n) : n in N_LIST(id_list_node)]; */
FORTUP(n_sym = (Node), N_LIST(id_list_node), ft2);
f_part = tup_with(f_part, (char *) N_UNQ(n_sym));
ENDFORTUP(ft2);
ENDFORTUP(ft1);
v_index = linearize_record(f_part, v_node);
/* case_range := [first_field, first_field+#f_part-1, v_index]; */
case_range = tup_new(3);
case_range[1] = (char *) first_field;
case_range[2] = (char *)(first_field + tup_size(f_part) - 1);
case_range[3] = (char *) v_index;
/* table :=
* [ [a, if b = index then case_range else b end]: [a, b] in
* table ];
*/
FORTUPI(tup = (Tuple), table, i, ft1);
b = (int) tup[2];
if (b == index) {
tup4 = tup_new(4);
tup4[1] = tup[1];
tup4[2] = case_range[1];
tup4[3] = case_range[2];
tup4[4] = case_range[3];
ntable[i] = (char *) tup4;
}
ENDFORTUP(ft1);
if (max_field_offset < CURRENT_FIELD_OFFSET) {
max_field_offset = CURRENT_FIELD_OFFSET;
}
index += 1;
}
CURRENT_FIELD_OFFSET = max_field_offset;
variant_offset = segment_get_maxpos(VARIANT_TABLE);
/* VARIANT_TABLE +:= [FIELD_NUMBER(name)]
* +/[ [a, b, c, d]: [a, [b, c, d]] in table ];
*/
/* this code was added because of a test like :
*
* type x (a, b : integer) is record
* case a is ...
* when others =>
* case b is
* when others => ...;
* end case;
* end case;
* end record;
*
* The inner case does not refer explictly to "b". Therefore in the
* tree its name is not set. In this case "name" is null. On acf2,
* the generated value for FIELD_NUMBER (name) was anything. On lang1
* there was an internal error (null pointer dereference).
* Now in this case, the value is set to 0
*/
if (name == (Symbol) 0) {
segment_put_int(VARIANT_TABLE, 0);
}
else {
segment_put_int(VARIANT_TABLE, (int)FIELD_NUMBER(name));
}
FORTUP(tup = (Tuple), ntable, ft1);
segment_put_int(VARIANT_TABLE, (int) tup[1]);
segment_put_int(VARIANT_TABLE, (int) tup[2]);
segment_put_int(VARIANT_TABLE, (int) tup[3]);
segment_put_int(VARIANT_TABLE, (int) tup[4]);
ENDFORTUP(ft1);
return variant_offset;
}
else {
return - 1; /* = no variant part */
}
}
static int discr_dep_subtype(Node decl) /*;discr_dep_subtype*/
{
/*
* This procedure takes care of the special type templates
* used for subtypes whose constraints depends on the discriminants
* of the enclosing record.
*
* The templates produced are TT_D_RECORD and TT_D_ARRAY.
*
* return TRUE in that case, FALSE if not a discr_dep_subtype.
*/
Node id_node, low, high, lbd, ubd, de, discr_value_node;
Symbol type_name, type_mark, indx_type, discr_type, comp_type, field_name;
Tuple constraint, tup, index_list, field_map, discr_list;
int varying_size_flag, max_nb_elem, nb_dim, tsize, i, n;
Fortup ft1;
Const min_low, max_high;
Segment stemplate;
int discr_depends, discr_value; /* used for get_discr values */
struct tt_d_type *tt_d_type_ptr;
#ifdef TRACE
if (debug_flag)
gen_trace_node("DISCR_DEP_SUBTYPE", decl);
#endif
id_node = N_AST1(decl);
type_name = N_UNQ(id_node);
type_mark = base_type(type_name);
constraint = get_constraint(type_name);
varying_size_flag = FALSE;
stemplate = (Segment) 0;
switch((int) constraint[1]) {
case(co_access):
INTERNAL_ACCESSED_TYPES = tup_with(INTERNAL_ACCESSED_TYPES,
(char *) DESIGNATED_TYPE(type_name));
compile(decl);
return FALSE;
case(co_index):
tup = SIGNATURE(type_name);
index_list = (Tuple) tup[1];
comp_type = (Symbol) tup[2];
max_nb_elem = 1;
FORTUP(indx_type = (Symbol), index_list, ft1);
tup = SIGNATURE(indx_type);
low = (Node) tup[2];
high = (Node) tup[3];
if (is_discr_ref(low)) {
varying_size_flag = TRUE;
discr_type = N_TYPE(low);
tup = SIGNATURE(discr_type);
low = (Node) tup[2];
}
if (is_discr_ref(high)) {
varying_size_flag = TRUE;
discr_type = N_TYPE(high);
tup = SIGNATURE(discr_type);
high = (Node) tup[3];
}
min_low = get_ivalue(low);
max_high = get_ivalue(high);
if (max_nb_elem >= 0
&& min_low->const_kind != CONST_OM
&& max_high->const_kind != CONST_OM) {
max_nb_elem *= get_ivalue_int(high) - get_ivalue_int(low) + 1;
}
else {
max_nb_elem = -1;
}
ENDFORTUP(ft1);
if (!varying_size_flag) {
compile(decl);
return FALSE;
}
nb_dim = tup_size(index_list);
tsize = TYPE_SIZE(comp_type);
TYPE_SIZE(type_name) = (max_nb_elem < 0 || tsize < 0) ? -1
: max_nb_elem * tsize;
TYPE_KIND(type_name) = TT_D_ARRAY;
reference_of(type_mark);
/* template := [TT_D_ARRAY, size_of(type_name)]+ref+[nb_dim]; */
stemplate = template_new(TT_D_ARRAY, size_of(type_name),
WORDS_D_TYPE, TT_PTR(&tt_d_type_ptr));
tt_d_type_ptr->dbase = REFERENCE_SEGMENT;
tt_d_type_ptr->doff = REFERENCE_OFFSET;
tt_d_type_ptr->nb_discr_d = nb_dim;
FORTUP(indx_type = (Symbol), index_list, ft1);
tup = SIGNATURE(indx_type);
low = (Node) tup[2];
high = (Node) tup[3];
/* template +:= get_discr(low); template +:= get_discr(high); */
get_discr(low, &discr_depends, &discr_value);
segment_put_int(stemplate, discr_depends);
segment_put_int(stemplate, discr_value);
get_discr(high, &discr_depends, &discr_value);
segment_put_int(stemplate, discr_depends);
segment_put_int(stemplate, discr_value);
ENDFORTUP(ft1);
break;
case(co_discr):
field_map = (Tuple) constraint[2];
n = tup_size(field_map);
for (i = 1; i <= n; i += 2) {
de = (Node) field_map[i+1];
varying_size_flag |= is_discr_ref(de);
}
if (!varying_size_flag) {
compile(decl);
return FALSE;
}
TYPE_KIND(type_name) = TT_D_RECORD;
TYPE_SIZE(type_name) = TYPE_SIZE(type_mark);
/* template := [TT_D_RECORD, size_of(type_name)]+ref+[#field_map]; */
stemplate = template_new(TT_D_RECORD, size_of(type_name),
WORDS_D_TYPE, TT_PTR(&tt_d_type_ptr));
reference_of(type_mark);
tt_d_type_ptr->dbase = REFERENCE_SEGMENT;
tt_d_type_ptr->doff = REFERENCE_OFFSET;
/* In SETL, want number of entries in field map; in C, this
* is number of entries in tuple used for for field map divided
* by two, since two elements are required for each single entry
* (domain and range values) in SETL version.
*/
tt_d_type_ptr->nb_discr_d = tup_size(field_map) / 2;
/* obtain discriminants in same order as in unconstrained type */
tup = SIGNATURE(type_mark);
discr_list = (Tuple) tup[3];
FORTUP(field_name = (Symbol), discr_list, ft1);
discr_value_node = discr_map_get(field_map, field_name);
if (N_KIND (discr_value_node) == as_qual_range) {
N_TYPE (discr_value_node) = root_type(TYPE_OF (field_name));
}
/* template +:= get_discr(discr_value); */
get_discr(discr_value_node, &discr_depends, &discr_value);
segment_put_int(stemplate, discr_depends);
segment_put_int(stemplate, discr_value);
ENDFORTUP(ft1);
break;
case(co_range):
lbd = (Node) constraint[2];
ubd = (Node) constraint[3];
if (is_discr_ref(lbd) || is_discr_ref(ubd)) {
/* can only be an anonymous type for an index of a TT_D_ARRAY
* no explicit template built for it
*/
break;
}
else {
compile(decl);
}
return FALSE;
default:
return FALSE;
}
if (stemplate != (Segment) 0) {
install_type(type_name, stemplate, FALSE);
}
return varying_size_flag;
}
static void get_discr(Node node, int *discr_depends, int *discr_value)
/*;get_discr*/
{
/* discr_depends and discr_value are used to return values corresponding
* to use of tuple for SETL return value
*/
/*
* if the expression depends on a discriminant, then returns
* [ 1, field number of the discriminant ]
* otherwise return
* [ 0, value of the discriminant ]
*
*/
Symbol discr;
int fn;
#ifdef TRACE
if (debug_flag)
gen_trace_node("GET_DISCR", node);
#endif
if (is_discr_ref(node)) {
if (N_KIND(node) == as_qual_range)
node = N_AST1(node);
discr = N_UNQ(node);
fn = (int) FIELD_NUMBER(discr);
gen_kvc(I_PUSH_IMMEDIATE, mu_byte, int_const(fn), "discr. ref.");
*discr_depends = TRUE;
*discr_value = fn;
return;
}
else {
gen_value(node);
*discr_depends = FALSE;
*discr_value = 0;
return;
}
}
static void eval_max_size(Symbol type_name, Tuple discr_subtypes)
/*;eval_max_size*/
{
Symbol discr, type_mark, comp_type, indx_type;
int discr_low, discr_high, fn;
Node low_node, high_node;
Tuple constraint, index_list, tup;
#ifdef TRACE
if (debug_flag)
gen_trace_symbol("EVAL_MAX_SIZE", type_name);
#endif
if (size_of(type_name) != -1) {/* static, already evaluated */
return;
}
type_mark = TYPE_OF(type_name);
constraint = get_constraint(type_name);
switch((int) constraint[1]) {
case(co_access):
break;
case(co_index):
comp_type = (Symbol) COMPONENT_TYPE(type_mark);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, type_name);
/* WORD_OFF is(obscure) macro defined in type.h to get
* offset(in ints) to object_size field
*/
gen_kic(I_ADD_IMMEDIATE, mu_word, WORD_OFF(tt_i_range, object_size),
"Object size");
gen_s(I_PUSH_EFFECTIVE_ADDRESS, comp_type);
gen_kic(I_ADD_IMMEDIATE, mu_word, WORD_OFF(tt_i_range, object_size),
"Compon. size");
gen_k(I_DEREF, kind_of(symbol_integer));
tup = INDEX_TYPES(type_name);
index_list = tup_copy(tup);
while(tup_size(index_list) != 0) {
indx_type = (Symbol) tup_fromb(index_list);
tup = SIGNATURE(indx_type);
low_node = (Node) tup[2];
high_node = (Node) tup[3];
discr_low = is_discr_ref(low_node);
discr_high = is_discr_ref(high_node);
if (!(discr_low | discr_high)) {
gen_s(I_PUSH_EFFECTIVE_ADDRESS, indx_type);
gen_kv(I_ATTRIBUTE, ATTR_T_LENGTH, int_const(0));
}
else {
if (discr_high) {
if (N_KIND(high_node) == as_qual_range)
high_node = N_AST1(high_node);
discr = N_UNQ(high_node);
fn = (int) FIELD_NUMBER(discr) + 1;
/* field # start from 0 */
if (base_type (indx_type) == ((Symbol) discr_subtypes [fn]))
gen_s(I_PUSH_EFFECTIVE_ADDRESS, TYPE_OF(indx_type));
else
gen_s(I_PUSH_EFFECTIVE_ADDRESS,
(Symbol) discr_subtypes[fn]);
gen_kv(I_ATTRIBUTE, ATTR_T_LAST, int_const(0));
}
else {
if (base_type (indx_type) == (N_TYPE (high_node)))
gen_s(I_PUSH_EFFECTIVE_ADDRESS, TYPE_OF(indx_type));
else
gen_s(I_PUSH_EFFECTIVE_ADDRESS, N_TYPE (high_node));
gen_kv(I_ATTRIBUTE, ATTR_T_LAST, int_const(0));
}
if (discr_low) {
if (N_KIND(low_node) == as_qual_range)
low_node = N_AST1(low_node);
discr = N_UNQ(low_node);
fn = (int) FIELD_NUMBER(discr) + 1;
/* field # start from 0 */
if (base_type (indx_type) == ((Symbol) discr_subtypes [fn]))
gen_s(I_PUSH_EFFECTIVE_ADDRESS, TYPE_OF(indx_type));
else
gen_s(I_PUSH_EFFECTIVE_ADDRESS,
(Symbol) discr_subtypes[fn]);
gen_kv(I_ATTRIBUTE, ATTR_T_FIRST, int_const(0));
}
else {
if (base_type (indx_type) == (N_TYPE (low_node)))
gen_s(I_PUSH_EFFECTIVE_ADDRESS, TYPE_OF(indx_type));
else
gen_s(I_PUSH_EFFECTIVE_ADDRESS, N_TYPE (low_node));
gen_kv(I_ATTRIBUTE, ATTR_T_FIRST, int_const(0));
}
gen_k(I_SUB, kind_of(symbol_integer));
gen_ki(I_ADD_IMMEDIATE, kind_of(symbol_integer), 1);
}
gen_k(I_MUL, kind_of(symbol_integer));
}
gen_kc(I_MOVE, mu_word, "update tt size");
break;
case(co_discr):
break; /* should be no problem as the TT_D_RECORD is
constrained */
case(co_range):
break;
}
}